#pragma once

#include "Lock.hpp"
#include "Thread.hpp"
#include "Sem.hpp"
#include "Log.hpp"
#include "Task.hpp"
#include <iostream>
#include <vector>
#include <queue>
#include <unistd.h>
#include <semaphore.h>

const int g_def_capacity = 5;
const int g_def_p_thread_num = 3;
const int g_def_c_thread_num = 3;

template <class T>
class ThreadPool
{
public:
    ThreadPool(int capacity = g_def_capacity, int p_thread_num = g_def_p_thread_num, int c_thread_num = g_def_c_thread_num)
        : _capacity(capacity)
        , _ring_queue(capacity, T())
        , _p_thread_num(p_thread_num)
        , _c_thread_num(c_thread_num)
        , _c_step(0)
        , _p_step(0)
        , _sem_space(capacity)
        , _sem_data(0)
        , _mtx_p()
        , _mtx_c()
    {
        // 创建生产者线程
        for(int i = 1; i <= _p_thread_num; ++i)
        {
            std::string name = "Product Thread ";
            name += std::to_string(i);
            _ptr_thread.push_back(new Thread(name, product, (void*)this));
            logMessage(DEBUG, "成功启动一个生产者线程: %s\n", name.c_str());
        }

        // 创建消费者线程
        for(int i = 1; i <= _c_thread_num; ++i)
        {
            std::string name = "Consume Thread ";
            name += std::to_string(i);
            _ptr_thread.push_back(new Thread(name, consume, (void*)this));
            logMessage(DEBUG, "成功启动一个消费者线程: %s\n", name.c_str());
        }
    }
    
    // 析构函数 -- delete线程指针
    ~ThreadPool()
    {
        for(const auto& iter : _ptr_thread)
        {
            delete iter;
        }
    }

private:
    // 消费者线程函数
    static void *product(void *args)
    {
        ThreadData *pdata = static_cast<ThreadData *>(args);
        ThreadPool<T> *ptr = static_cast<ThreadPool<T> *>(pdata->_args);

        // 1. 制作任务
        int x = rand() % 20 + 1;
        usleep(200);   // 短时间休眠提高数据随机性
        int y = rand() % 20 + 1;

        T task(x, y, [](int x, int y)->int{
            return x + y;
        });
        logMessage(DEBUG, "[%s] 成功制作一个任务: %d + %d = ?\n", pdata->name().c_str(), x, y);

        while(true)
        {
            // 2. 生产者写数据，获取空间信号量
            ptr->_sem_space.p();   

            // 3. 生产者拿锁，避免生产者线程之间出现线程不安全问题
            ptr->_mtx_p.lock();

            // 4. 将任务插入环形队列
            ptr->_ring_queue[ptr->_p_step++] = task;
            ptr->_p_step %= ptr->_capacity;   // 更新下一个插入位置的下标
            logMessage(DEBUG, "[%s] 成功将一个任务插入到环形队列: %d + %d = ?\n", pdata->name().c_str(), x, y);

            // 5. 生产者释放锁
            ptr->_mtx_p.unlock();

            // 6. 释放数据信号量
            ptr->_sem_data.v();
        }
    }

    static void *consume(void *args)
    {
        ThreadData *pdata = static_cast<ThreadData *>(args);
        ThreadPool<T> *ptr = static_cast<ThreadPool<T> *>(pdata->_args);

        T task;  // 接受任务的对象
        while(true)
        {
            // 1. 申请数据信号量
            ptr->_sem_data.p();

            // 2. 申请消费者锁
            ptr->_mtx_c.lock();

            // 3. 读取任务
            task = ptr->_ring_queue[ptr->_c_step++];
            ptr->_c_step %= ptr->_capacity;

            // 4. 执行任务
            logMessage(DEBUG, "[%s] 成功执行任务: %d+%d=%d\n", pdata->name().c_str(), task.get_x(), task.get_y(), task());

            // 5. 消费者释放锁
            ptr->_mtx_c.unlock();

            // 6. 释放空间信号量
            ptr->_sem_space.v();
        }
    }

private:
    std::vector<Thread*> _ptr_thread; // 指向线程的指针
    int _capacity;                // 环形队列的最大容量
    std::vector<T> _ring_queue;   // 使用vector模拟的环形队列
    int _p_thread_num;   // 生产者线程数
    int _c_thread_num;   // 消费者线程数
    int _c_step;         // 消费者读取数据的下标位置
    int _p_step;         // 生产者生产数据的下标位置         
    Sem _sem_space;      // 空间信号量
    Sem _sem_data;       // 数据信号量
    Lock _mtx_p;         // 防止生产者线程之间出现线程不安全的锁
    Lock _mtx_c;         // 防止消费者线程之间出现线程不安全的锁
};